package top.withwings.bonus.bonus.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.withwings.bonus.bonus.pojo.BonusForm;
import top.withwings.bonus.bonus.pojo.FinalBonus;
import top.withwings.bonus.bonus.pojo.Rate;
import top.withwings.bonus.bonus.pojo.bonus.rule.ExpirationCloseBonusRule;
import top.withwings.bonus.bonus.pojo.bonus.rule.HighPriceBonusRule;
import top.withwings.bonus.bonus.pojo.bonus.rule.OnSaleBonusRule;
import top.withwings.bonus.bonus.repo.BonusFormRepo;
import top.withwings.bonus.bonus.repo.FinalBonusRepo;
import top.withwings.bonus.bonus.util.BonusDateUtils;
import top.withwings.bonus.common.pojo.PageParam;
import top.withwings.bonus.common.pojo.Period;
import top.withwings.bonus.common.pojo.User;
import top.withwings.bonus.common.service.UserService;

import java.util.Arrays;
import java.util.Date;
import java.util.List;

@Service
public class BonusComputationService {


    @Autowired
    private RuleService ruleService;

    @Autowired
    private BonusFormRepo bonusFormRepo;

    @Autowired
    private FinalBonusRepo finalBonusRepo;

    @Autowired
    private BonusFormService bonusFormService;

    @Autowired
    private UserService userService;

    private final static  FinalRateStrategy FINAL_RATE_STRATEGY = FinalRateStrategy.Max;



    public void computeSingleBonus(BonusForm form) {

        Rate highPriceBonusRate = computeHighPriceBonusRate(form);
        Rate expirationCloseBonusRate = computeExpirationCloseBonusRate(form);
        Rate onSaleBonusRate = computeOnSaleBonusRate(form);
        form.setSingleRates(Arrays.asList(highPriceBonusRate, expirationCloseBonusRate,onSaleBonusRate ));

        Rate finalRate = FINAL_RATE_STRATEGY.decide(form.getSingleRates());
        form.setFinalRate(finalRate);

        Date now = new Date();
        form.setComputedDate(now);

        bonusFormRepo.update(form);
    }

    public void computeFinalBonus(String yearMonth) {
        for (User user : userService.findAll()) {
            if(user.isAdmin()) continue;
            FinalBonus finalBonus = finalBonusRepo.gather(yearMonth,user.getId());
            finalBonus.setSalesman(user);
            this.computeFinalBonus(finalBonus);
        }
    }



    public void computeFinalBonus(FinalBonus finalBonus) {

        double singleSum = finalBonus.getSingleSum();
        double makeUpSum = finalBonus.getMakeUpSum();
        double grossAmount = finalBonus.getGrossAmount();
        Rate grossAmountRate = ruleService.findGrossAmountRule().applyOn(finalBonus.getGrossAmount());
        finalBonus.setGrossAmountRate(grossAmountRate);
        finalBonus.setFinalResult(singleSum + makeUpSum + grossAmountRate.getValue() / 100 * grossAmount);
        finalBonusRepo.delete(finalBonus.getSalesman().getId(),finalBonus.getYearMonth());
        finalBonusRepo.save(Arrays.asList(finalBonus));
    }



    private Rate computeOnSaleBonusRate(BonusForm form) {
        OnSaleBonusRule rule = ruleService.findOnSaleRule(form);
        if (rule == null) {
            return Rate.NOT_APPLIED;
        } else {
            return rule.applyOn(form);
        }

    }

    private Rate computeExpirationCloseBonusRate(BonusForm form) {
        ExpirationCloseBonusRule rule = ruleService.findCloseExpirationRule(form);
        if (rule == null) {
            return Rate.NOT_APPLIED;
        } else {
            return rule.applyOn(form);
        }

    }

    private Rate computeHighPriceBonusRate(BonusForm form) {
        HighPriceBonusRule rule = ruleService.findHighPriceRule(form);
        if (rule == null) {
            return Rate.NOT_APPLIED;
        } else {
            return rule.applyOn(form);
        }

    }


    public void computeSingleBonus(String yearMonth) {
        Period period = BonusDateUtils.fromYearMonth(yearMonth);
        List<BonusForm> bonusForms = bonusFormService.search(new PageParam(0,Integer.MAX_VALUE),null,period.getStart(),period.getEnd());
        for (BonusForm bonusForm : bonusForms) {
            this.computeSingleBonus(bonusForm);
        }
    }
}


enum FinalRateStrategy {

    Sum("多项单项提成求和") {
        public Rate decide(List<Rate> singleRates) {
            double rateValue = 0;
            for (Rate singleRate : singleRates) {
                rateValue+=singleRate.getValue();
            }
            if(rateValue != 0){
                return new Rate(Rate.TYPE_NORMAL,rateValue);
            }else {
                return new Rate(Rate.TYPE_NOT_APPLIED,rateValue);
            }

        }
    },

    Max("多项单项提成中取最大值") {
        public Rate decide(List<Rate> singleRates) {
            double rateValue = 0;
            for (Rate singleRate : singleRates) {
                if(rateValue<singleRate.getValue()){
                    rateValue = singleRate.getValue();
                }
            }
            if(rateValue != 0){
                return new Rate(Rate.TYPE_NORMAL,rateValue);
            }else {
                return new Rate(Rate.TYPE_NOT_APPLIED,rateValue);
            }
        }
    },

    Priority("多项单项提成中取优先级高的") {
        public Rate decide(List<Rate> singleRates) {
            for (Rate rate : singleRates) {
                if (rate.getType() >= 0) {
                    return rate;
                }
            }
            return new Rate(Rate.TYPE_NO_SUITABLE, 0);
        }
    };

    
    private String description;

    FinalRateStrategy(String description) {
        this.description = description;
    }

    public String getDescription() {
        return description;
    }


    public Rate decide(List<Rate> singleRates) {
        return Rate.NOT_APPLIED;
    }
}